package com.idp.app.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.idp.app.dto.AppUserDto;
import com.idp.app.dto.AppUserSearchDto;
import com.idp.app.entity.AppUserEntity;
import com.idp.app.mapper.AppUserMapper;
import com.idp.app.service.AppUserService;
import com.idp.common.constants.RedisKeyConstant;
import com.idp.common.enums.MessageEnum;
import com.idp.common.enums.RegisterTypeEnum;
import com.idp.common.enums.UserStatusEnum;
import com.idp.common.enums.UserTypeEnum;
import com.idp.common.error.SystemException;
import com.idp.common.model.LoginInfo;
import com.idp.common.model.PageModel;
import com.idp.common.redis.RedisCache;
import com.idp.common.token.PhoneAuthenticationToken;
import com.idp.common.token.service.TokenService;
import com.idp.common.utils.ContextUtil;
import com.idp.common.utils.EncodeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * APP用户Service实现类
 * @author King
 */
@Service("appUserService")
public class AppUserServiceImpl implements AppUserService {

	private static final Logger log = LoggerFactory.getLogger(AppUserServiceImpl.class);

	@Autowired
	private AppUserMapper appUserMapper;
	@Autowired
	private TokenService tokenService;
	@Autowired
	private RedisCache redisCache;
	@Autowired
	private AuthenticationManager authenticationManager;

	@Override
	public PageModel<AppUserDto> findByPage(AppUserSearchDto appUserSearchDto) {

		PageModel<AppUserDto> page = new PageModel<AppUserDto>();

		if(appUserSearchDto.getRegisterTimeEnd() != null) {
			appUserSearchDto.setRegisterTimeEnd(DateUtil.endOfDay(appUserSearchDto.getRegisterTimeEnd()));
		}

		page.setList(appUserMapper.getList(appUserSearchDto));

		return page;
	}

	@Override
	public AppUserDto getById(String id) {

		if(ObjectUtil.isEmpty(id)) {

			throw new SystemException(MessageEnum.PARAM_ERROR);
		}

		AppUserDto appUserDto = appUserMapper.getById(id);

		if(appUserDto == null) {

			throw new SystemException(MessageEnum.DATA_NOT_EXIST);
		}

		return appUserDto;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void update(AppUserDto appUserDto) {

		AppUserEntity updateUser = new AppUserEntity();

		if(StrUtil.isNotEmpty(appUserDto.getId())) {

			updateUser.setId(appUserDto.getId());
		}
		else {

			updateUser.setId(ContextUtil.getLoginUserId());
		}

		if(StrUtil.isNotEmpty(appUserDto.getUname())) {

			LambdaQueryWrapper<AppUserEntity> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.ne(AppUserEntity::getStatus, UserStatusEnum.DELETED.code);
			queryWrapper.eq(AppUserEntity::getUname, appUserDto.getUname());
			AppUserEntity user = appUserMapper.selectOne(queryWrapper);

			if(user != null && !user.getId().equals(updateUser.getId())) {
				throw new SystemException("用户名已存在");
			}

			updateUser.setUname(appUserDto.getUname());
		}

		if(StrUtil.isNotEmpty(appUserDto.getPhone())) {

			String cacheCode = redisCache.getObject(RedisKeyConstant.PHONE_FOLDER + appUserDto.getPhone());

			if(appUserDto.getCode().equals(cacheCode)) {

				LambdaQueryWrapper<AppUserEntity> queryWrapper = new LambdaQueryWrapper<>();
				queryWrapper.ne(AppUserEntity::getStatus, UserStatusEnum.DELETED.code);
				queryWrapper.eq(AppUserEntity::getPhone, appUserDto.getPhone());
				AppUserEntity user = appUserMapper.selectOne(queryWrapper);

				if(user != null && !user.getId().equals(updateUser.getId())) {
					throw new SystemException("此手机号已绑定其他用户");
				}
			}
			else {

				throw new SystemException("验证码错误");
			}

			updateUser.setPhone(appUserDto.getPhone());
		}

		if(StrUtil.isNotEmpty(appUserDto.getStatus())) {

			updateUser.setStatus(appUserDto.getStatus());
		}

		if(StrUtil.isNotEmpty(appUserDto.getUserPhoto())) {

			updateUser.setUserPhoto(appUserDto.getUserPhoto());
		}

		if(StrUtil.isNotEmpty(appUserDto.getNickname())) {

			updateUser.setNickname(appUserDto.getNickname());
		}

		if(StrUtil.isNotEmpty(appUserDto.getSex())) {

			updateUser.setSex(appUserDto.getSex());
		}

		if(appUserDto.getBirthday() != null) {

			updateUser.setBirthday(appUserDto.getBirthday());
		}

		if(StrUtil.isNotEmpty(appUserDto.getSignature())) {

			updateUser.setSignature(appUserDto.getSignature());
		}

		appUserMapper.updateById(updateUser);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public LoginInfo registerUser(AppUserDto appUserDto) {

		String cacheCode = redisCache.getObject(RedisKeyConstant.PHONE_FOLDER + appUserDto.getPhone());

		if(appUserDto.getCode().equals(cacheCode)) {

			LambdaQueryWrapper<AppUserEntity> queryPhone = new LambdaQueryWrapper<>();
			queryPhone.ne(AppUserEntity::getStatus, UserStatusEnum.DELETED.code);
			queryPhone.eq(AppUserEntity::getPhone, appUserDto.getPhone());
			AppUserEntity userCheckPhone = appUserMapper.selectOne(queryPhone);

			if(userCheckPhone != null) {

				throw new SystemException("手机号码已存在");
			}

			LambdaQueryWrapper<AppUserEntity> queryUsername = new LambdaQueryWrapper<>();
			queryUsername.ne(AppUserEntity::getStatus, UserStatusEnum.DELETED.code);
			queryUsername.eq(AppUserEntity::getUname, appUserDto.getUname());
			AppUserEntity userCheckUsername = appUserMapper.selectOne(queryUsername);

			if(userCheckUsername != null) {

				throw new SystemException("用户名已存在");
			}

			AppUserEntity appUserEntity = BeanUtil.toBean(appUserDto, AppUserEntity.class);
			appUserEntity.setId(IdUtil.simpleUUID());
			appUserEntity.setPwd(EncodeUtil.encryptPassword(appUserDto.getPwd()));
			appUserEntity.setNickname("用户");
			appUserEntity.setStatus(UserStatusEnum.NORMAL.code);
			appUserEntity.setRegisterType(RegisterTypeEnum.APP_PHONE.code);
			appUserEntity.setRegisterTime(new Date());
			appUserMapper.insert(appUserEntity);

			try {
				PhoneAuthenticationToken authenticationToken = new PhoneAuthenticationToken(appUserDto.getPhone(), "");
				Authentication authentication = authenticationManager.authenticate(authenticationToken);

				LoginInfo loginInfo = (LoginInfo) authentication.getPrincipal();
				loginInfo.setUserType(UserTypeEnum.MOBILE.code);
				tokenService.saveToken(loginInfo);

				return loginInfo;
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				throw new SystemException(e.getMessage());
			}
		} else {

			throw new SystemException("验证码错误");
		}
	}

	@Override
	public AppUserDto getUserInfo() {

		LoginInfo loginInfo = ContextUtil.getLoginUser();

		if(loginInfo != null) {

			return getById(loginInfo.getId());
		}

		return null;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updatePwd(String oldPwd, String newPwd, String checkOldPwd) {

		AppUserEntity user = appUserMapper.selectById(ContextUtil.getLoginUserId());

		if(user != null) {

			if(StrUtil.isNotEmpty(user.getPwd()) && "Y".equals(checkOldPwd)) {

				String oldEPwd = EncodeUtil.encryptPassword(oldPwd);

				if(!user.getPwd().equals(oldEPwd)) {

					throw new SystemException("旧密码错误");
				}
			}

			AppUserEntity updateUser = new AppUserEntity();
			updateUser.setId(user.getId());
			String newEPwd = EncodeUtil.encryptPassword(newPwd);
			updateUser.setPwd(newEPwd);

			appUserMapper.updateById(updateUser);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeUser() {

		LoginInfo loginInfo = tokenService.removeToken();

		if(loginInfo != null) {

			AppUserEntity user = new AppUserEntity();
			user.setId(loginInfo.getId());
			user.setStatus(UserStatusEnum.DELETED.code);

			appUserMapper.updateById(user);
		}

	}
}
